package com.yeskery.nut.scan;

import com.yeskery.nut.annotation.aop.Aspect;
import com.yeskery.nut.annotation.bean.Component;
import com.yeskery.nut.annotation.bean.Configuration;
import com.yeskery.nut.annotation.bean.Import;
import com.yeskery.nut.annotation.environment.ConfigurationProperties;
import com.yeskery.nut.annotation.web.Controller;
import com.yeskery.nut.annotation.web.ControllerAdvice;
import com.yeskery.nut.annotation.web.RestController;
import com.yeskery.nut.annotation.web.RestControllerAdvice;
import com.yeskery.nut.application.ApplicationType;
import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.application.NutWebConfigure;
import com.yeskery.nut.bean.BeanRegister;
import com.yeskery.nut.bean.FactoryBeanRegister;
import com.yeskery.nut.core.*;
import com.yeskery.nut.plugin.BasePluginInitializer;
import com.yeskery.nut.plugin.BindContext;
import com.yeskery.nut.scan.advice.AnnotationControllerAdviceHandler;
import com.yeskery.nut.scan.bean.*;
import com.yeskery.nut.scan.controller.AnnotationControllerHandler;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

/**
 * 注解扫描处理器
 * @author sprout
 * 2022-06-14 19:38
 */
public class AnnotationScanHandler implements Scanner<Void> {

    /** {@link Request}bean名称 */
    private static final String REQUEST_BEAN_NAME = "request";

    /** {@link com.yeskery.nut.core.Session}bean名称 */
    private static final String SESSION_BEAN_NAME = "session";

    /** {@link com.yeskery.nut.core.ServerContext}bean名称 */
    private static final String SERVER_CONTEXT_BEAN_NAME = "serverContext";

    /** Nut应用对象 */
    private final NutApplication nutApplication;

    /** 注解Class扫描器 */
    private final AnnotationClassScanner annotationClassScanner;

    /**
     * 构建注解扫描处理器
     * @param nutApplication Nut应用对象
     * @param basePackages 扫描的基础路径
     * @param pluginInitializer 插件初始化器
     * @param bindContext 插件的绑定上下文对象
     */
    public AnnotationScanHandler(NutApplication nutApplication, Set<String> basePackages,
                                 BasePluginInitializer pluginInitializer, BindContext bindContext) {
        this.nutApplication = nutApplication;
        annotationClassScanner = new PluginSupportAnnotationClassScanner(nutApplication, basePackages,
                pluginInitializer, bindContext);
        registerDefaultAnnotationHandler();

        if (ApplicationType.isWebApplicationType(nutApplication.getApplicationMetadata().getApplicationType())) {
            // 向web应用上下文注册Request处理类
            FactoryBeanRegister factoryBeanRegister = (FactoryBeanRegister) nutApplication.getWebApplicationContext();
            factoryBeanRegister.registerBean(REQUEST_BEAN_NAME, new WebRequestHolder(), Request.class, WebRequestHolder.class);
            factoryBeanRegister.registerBean(SESSION_BEAN_NAME, new WebSessionHolder(), Session.class, WebSessionHolder.class);
            factoryBeanRegister.registerBean(SERVER_CONTEXT_BEAN_NAME, new WebServerContextHolder(), ServerContext.class, WebServerContextHolder.class);
        }
    }

    @Override
    public Collection<Void> scan() {
        annotationClassScanner.scan();
        return Collections.emptySet();
    }

    /**
     * 注册默认注解处理器
     */
    private void registerDefaultAnnotationHandler() {
        // 注册Aspect注解
        annotationClassScanner.registerAnnotationHandler(Aspect.class, new AnnotationAspectHandler(nutApplication.getApplicationContext()));

        // 注册Import注解
        annotationClassScanner.registerAnnotationHandler(Import.class, new AnnotationImportHandler());

        // 注册Configuration注解
        annotationClassScanner.registerAnnotationHandler(Configuration.class,
                new AnnotationConfigurationHandler((FactoryBeanRegister) nutApplication.getApplicationContext(),
                        nutApplication.getApplicationContext()));

        // 注册ConfigurationProperties注解
        annotationClassScanner.registerAnnotationHandler(ConfigurationProperties.class,
                new AnnotationConfigurationPropertiesHandler((FactoryBeanRegister) nutApplication.getApplicationContext(),
                        nutApplication.getNutConfigure().getEnvironment()));

        // 注册Component注解
        AnnotationComponentHandler annotationComponentHandler = new AnnotationComponentHandler((BeanRegister) nutApplication.getApplicationContext());
        annotationClassScanner.registerAnnotationHandler(Component.class, annotationComponentHandler);

        if (ApplicationType.isWebApplicationType(nutApplication.getApplicationMetadata().getApplicationType())) {
            NutWebConfigure webConfigure = nutApplication.getNutWebConfigure();
            // 注册Controller与RestController注解
            AnnotationControllerHandler controllerHandler = new AnnotationControllerHandler(nutApplication, webConfigure.getControllerManager());
            annotationClassScanner.registerAnnotationHandler(Controller.class, controllerHandler);
            annotationClassScanner.registerAnnotationHandler(RestController.class, controllerHandler);

            // 注册ControllerAdvice与RestControllerAdvice注解
            AnnotationControllerAdviceHandler controllerAdviceHandler = new AnnotationControllerAdviceHandler(webConfigure.getPluginManager());
            annotationClassScanner.registerAnnotationHandler(ControllerAdvice.class, controllerAdviceHandler);
            annotationClassScanner.registerAnnotationHandler(RestControllerAdvice.class, controllerAdviceHandler);
        }
    }
}
